package com.geovis.emergency.spd.controller.pc;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.geovis.common.core.api.Result;
import com.geovis.emergency.spd.biz.iflytek.service.IflytekService;
import com.geovis.emergency.spd.biz.iflytek.thread.PushThread;
import com.geovis.emergency.spd.biz.pc.service.*;
import com.geovis.emergency.spd.biz.pc.wrapper.PcDrillDisasterEventWrapper;
import com.geovis.emergency.spd.entity.pc.entity.*;
import com.geovis.emergency.spd.entity.pc.pojo.enums.DisasterEventStatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.enums.ResponseTypeEnum;
import com.geovis.emergency.spd.entity.pc.pojo.enums.StatusEnum;
import com.geovis.emergency.spd.entity.pc.pojo.vo.DrillReportVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.PcDrillDisasterEventListVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.StatisticsEventVO;
import com.geovis.emergency.spd.entity.pc.pojo.vo.TreeVO;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 *
 * </p>
 *
 * @author Lonsho
 * @version 1.0
 * @date 2022/7/28
 */
@RestController
@RequestMapping("/pc/drillExport")
@RequiredArgsConstructor
@Api(value = "应急预案指挥模块-演练导出接口", tags = "应急预案指挥模块-演练导出接口")
@Slf4j
@Validated
public class DrillExportController {
    private final IDrillStatisticsService drillStatisticsService;
    private final IPcDrillDisasterService pcDrillDisasterService;

    private final IPcDrillKpiService pcDrillKpiService;
    private final IPcDrillDisasterEventService pcDrillDisasterEventService;
    private final IPcDutyService pcDutyService;

    private final IPcDrillDutyOrgService pcDrillDutyOrgService;
    private final IPcDrillDutyUserService pcDrillDutyUserService;
    private final IPcDrillPlanDetailService pcDrillPlanDetailService;
    private final IPcDrillPlanTaskService pcDrillPlanTaskService;

    private final IPcDrillExportService pcDrillExportService;

    private final IflytekService iflytekService;

    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "演练报告数据导出", notes = "演练报告数据导出接口")
    @PostMapping("drillReport/{pcDrillId}")
    public Result<DrillReportVO> drillReport(@PathVariable("pcDrillId") String pcDrillId){
        DrillReportVO drillReportVO = getDrillReport(pcDrillId);

        List<DrillReportVO.KpiVO> kpiData = pcDrillKpiService.list(
                Wrappers.lambdaQuery(PcDrillKpi.class)
                        .eq(PcDrillKpi::getPcDrillId, pcDrillId)
                        .orderByAsc(PcDrillKpi::getIdx)
        ).stream().map(s -> BeanUtil.toBean(s, DrillReportVO.KpiVO.class)).collect(Collectors.toList());
        drillReportVO.setKpiData(kpiData);
        return Result.ok(drillReportVO);
    }
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "演练方案数据导出", notes = "演练方案导出数据接口")
    @PostMapping("drillPlan/{pcDrillId}")
    public Result<DrillReportVO> drillPlan(@PathVariable("pcDrillId") String pcDrillId,
                                           @RequestParam(value = "eventId",required = false) String eventId,
                                           @RequestParam(value = "disasterId",required = false) String disasterId){
        DrillReportVO drillReportVO = getDrillReport(pcDrillId);

        if (StrUtil.isNotBlank(disasterId)){
            drillReportVO.setDisasterList(drillReportVO.getDisasterList().stream().filter(s -> s.getId().equals(disasterId)).collect(Collectors.toList()));
        }

        //指挥编组
        List<PcDrillDutyOrg> allDutyOrgList = pcDrillDutyOrgService.list(
                Wrappers.<PcDrillDutyOrg>lambdaQuery()
                        .orderByAsc(PcDrillDutyOrg::getIdx)
        );
        List<PcDrillDutyOrg> dutyOrgList = allDutyOrgList.stream().filter(s -> StatusEnum.FALSE.getCode().equals(s.getParentId())).collect(Collectors.toList());
        List<PcDrillDisasterEventListVO> disasterEventList = pcDrillDisasterEventService.getList(pcDrillId,
                StrUtil.format("{},{}", DisasterEventStatusEnum.IN_PROGRESS.getCode(), DisasterEventStatusEnum.COMPLETED.getCode()));

        List<PcDrillDisasterEvent> eventList = disasterEventList.stream().map(s -> BeanUtil.toBean(s, PcDrillDisasterEvent.class)).sorted(Comparator.comparing(PcDrillDisasterEvent::getSubmitTime)).collect(Collectors.toList());
        List<StatisticsEventVO> statisticsEventVoList = PcDrillDisasterEventWrapper.build(null, pcDrillPlanDetailService, pcDrillPlanTaskService, dutyOrgList).listVO(eventList);
        List<DrillReportVO.DisasterEventVO> reportEventList = Lists.newArrayList();

        for (StatisticsEventVO statisticsEvent : statisticsEventVoList) {
            if (ResponseTypeEnum.BROADCAST_EVENT.getCode().equals(statisticsEvent.getResponseType())){
                continue;
            }
            if (StrUtil.isNotBlank(eventId) && !statisticsEvent.getId().equals(eventId)){
                continue;
            }
            if (StrUtil.isBlank(statisticsEvent.getResponseAction())){
                statisticsEvent.setResponseAction("");
            }
            DrillReportVO.DisasterEventVO disasterEventVO = BeanUtil.toBean(statisticsEvent, DrillReportVO.DisasterEventVO.class);
            List<DrillReportVO.GroupVO> groupVoList = statisticsEvent.getDutyOrgList().stream().map(dutyOrgVO -> {
                DrillReportVO.GroupVO groupVO = new DrillReportVO.GroupVO();
                groupVO.setGroupName(dutyOrgVO.getOrgName());
                List<PcDrillDutyOrg> groupList = allDutyOrgList.stream().filter(s -> s.getAncestors().contains(dutyOrgVO.getId())).collect(Collectors.toList());
                List<PcDrillDutyUser> dutyList = pcDrillDutyUserService.list(
                        Wrappers.lambdaQuery(PcDrillDutyUser.class)
                                .isNotNull(PcDrillDutyUser::getDuty)
                                .in(PcDrillDutyUser::getPcDrillOrgId, groupList.stream().map(PcDrillDutyOrg::getId).collect(Collectors.toList()))
                );
                Map<String, List<PcDrillDutyUser>> stringListMap = IterUtil.toListMap(dutyList, PcDrillDutyUser::getDeptName);
                List<DrillReportVO.DutyVO> dutyContentList = Lists.newArrayList();
                int index = 0;
                for (Map.Entry<String, List<PcDrillDutyUser>> entry : stringListMap.entrySet()) {
                    Set<String> contentList = entry.getValue().stream().map(PcDrillDutyUser::getDuty).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
                    DrillReportVO.DutyVO dutyVO = new DrillReportVO.DutyVO();
                    dutyVO.setDeptName((++index)+"."+entry.getKey());
                    dutyVO.setDuty(StrUtil.join("、",contentList));
                    dutyContentList.add(dutyVO);
                }
                groupVO.setDutyList(dutyContentList);
                AtomicInteger taskCount = new AtomicInteger(0);
                groupVO.setDrillPlanList(
                        dutyOrgVO.getDrillPlanDetailList().stream().map(planDetailVO -> {
                            DrillReportVO.DrillPlanVO drillPlanVO = new DrillReportVO.DrillPlanVO();
                            drillPlanVO.setIdx(taskCount.incrementAndGet());
                            drillPlanVO.setTaskContent(planDetailVO.getContent());
                            return drillPlanVO;
                        }).collect(Collectors.toList())
                );
                return groupVO;
            }).collect(Collectors.toList());
            disasterEventVO.setGroupList(groupVoList);
            reportEventList.add(disasterEventVO);
        }
        drillReportVO.setDisasterEventList(reportEventList);
        PcDrillExport pcDrillExport = new PcDrillExport();
        pcDrillExport.setPcDrillId(pcDrillId);
        pcDrillExportService.save(pcDrillExport);

        List<PcDrillExport> list = pcDrillExportService.list(
                Wrappers.lambdaQuery(PcDrillExport.class)
                        .eq(PcDrillExport::getPcDrillId, pcDrillId)
                        .orderByDesc(PcDrillExport::getCreateTime)
        );
        //导出成功之后，将最后导出信息推送至科大
        PushThread.execute(()->{
            if(ObjectUtil.isNotEmpty(list)){
                iflytekService.updatePcDrill(pcDrillId,list.size(),list.get(0).getCreateTime());
            }else {
                iflytekService.updatePcDrill(pcDrillId,list.size(), LocalDateTime.now());
            }
        });

        return Result.ok(drillReportVO);
    }
    private DrillReportVO getDrillReport(String pcDrillId){
        DrillReportVO drillReportVO = drillStatisticsService.drillStatistics(pcDrillId);

        AtomicInteger disasterCount = new AtomicInteger();

        List<DrillReportVO.DisasterVO> disasterList = pcDrillDisasterService.list(
                Wrappers.lambdaQuery(PcDrillDisaster.class)
                        .eq(PcDrillDisaster::getPcDrillId, pcDrillId)
        ).stream().map(s -> {
            DrillReportVO.DisasterVO disasterVO = BeanUtil.toBean(s, DrillReportVO.DisasterVO.class);
            disasterVO.setIdx(disasterCount.incrementAndGet());
            return disasterVO;
        }).collect(Collectors.toList());
        drillReportVO.setDisasterList(disasterList);

        if(StrUtil.isBlank(drillReportVO.getPlanName())){
            drillReportVO.setPlanName("");
        }
        List<TreeVO> treeVOList = pcDutyService.dutyTree(pcDrillId, null,false);
        List<DrillReportVO.DutyOrgVO> dutyList = getDutyList(treeVOList,1);
        drillReportVO.setDutyOrgList(dutyList);
        return drillReportVO;
    }
    private List<DrillReportVO.DutyOrgVO> getDutyList(List<TreeVO> treeList,int level){
        List<DrillReportVO.DutyOrgVO>  list = Lists.newArrayList();
        if(ObjectUtil.isNotEmpty(treeList)) {
            for (TreeVO treeVO : treeList) {
                DrillReportVO.DutyOrgVO dutyOrgVO = new DrillReportVO.DutyOrgVO();
                if (StrUtil.isNotBlank(treeVO.getName())){
                    dutyOrgVO.setName(getTabChar(level -1)+treeVO.getName());
                    list.add(dutyOrgVO);
                }
                List<DrillReportVO.DutyOrgVO> dutyList = getDutyList(treeVO.getChildren(), level + 1);
                if (CollUtil.isNotEmpty(dutyList)){
                    list.addAll(dutyList);
                }

            }
        }
        return list;
    }
    private String getTabChar(int size){
        StringBuilder chart = new StringBuilder("|-");
        for(int i = 0;i < size;i++){
            chart.append("--");
        }
        return chart.toString();
    }
}
